(** Hardware Abstraction Layer *)

(** Load the SDL shared library and all necessary functions
    Load the OpenGL shared library and all necessary functions
    Example usage:
        let () = Hal.init ("/usr/lib/libGL.so")
        let () = Hal.init ("")
    @param path location of opengl shared library. If empty uses system default
    @raise Failure error-message*)
external init: path:string -> unit = "hal_init" "hal_init"


(***************************** Audio ******************************************)
(**
 * Note: No sound will be produced unless init_sound () has been called *and*
 * a window has been created. For command-line sound remove the SDL_init() call
 * in hal_init() [C source code in hal_stub.c]
 * *)
module Audio  = struct

    type sound = 
        (int, Bigarray.int16_signed_elt, Bigarray.c_layout) Bigarray.Array1.t

    type sample = None | Some of sound

    type voice = {
            source:           sample;
            mutable soundpos: int;
            mutable pitch:    float;
            mutable balance:  float;
            mutable volume:   float;
            mutable loop:     bool;
            mutable active:   bool;
        }

    let make_new_voice s =
        {       
            source = s;
            soundpos = 0;
            pitch = 1.0;
            balance = 0.0;
            volume = 1.0;
            loop = false;
            active = false
        }

    let maximum_number_of_samples = 4

    let maximum_number_of_voices  = 4

    let samples =
        Array.init maximum_number_of_samples (fun _ -> None)

    let voices =
        Array.init maximum_number_of_voices (fun _ -> make_new_voice None)

    let assign_sound_to_sample s i =
        samples.(i) <- Some s

    let assign_sample_to_voice s i =
        voices.(i) <- make_new_voice s

    let play_sound i b =
        voices.(i).active <- b

    let loop_sound i b =
        voices.(i).loop <- b

    let mix_voice s v =
        if v.active then
        let len = (Bigarray.Array1.dim s) in
        match v.source with
        | None -> ()
        | Some snd ->
            let lvol = v.volume *. (1.0 -. v.balance)/. 2.0
            and rvol = v.volume *. (1.0 +. v.balance)/. 2.0
            and sndlen = (Bigarray.Array1.dim snd) in
            let base = if v.loop then sndlen else max_int in
            for i = 0 to (len-1) do
                let pa = (float (i/2)) *. v.pitch in
                let k  = (truncate pa) in
                let l  = pa -. (floor pa) in
                let c1 = v.soundpos + 2*k in
                let c2 = c1 + 2 in
                if (c2 < sndlen) || v.loop then
                    let p1 = (1.0 -. l) *. (float snd.{c1 mod base})
                    and p2 = l *. (float snd.{c2 mod base}) in
                    let vol = if ((i land 2) = 0) then lvol else rvol in
                    s.{i} <- s.{i} + (truncate ((p1 +. p2) *. vol))
                else
                    v.soundpos <- sndlen
            done;
            v.soundpos <- v.soundpos + (truncate ((float len) *. v.pitch +. 0.5))

    let mix_callback s =
        Array.iter (mix_voice s) voices

    let () =
        Callback.register "mix_callback" mix_callback

    external init_sound: int -> int -> unit = "hal_init_sound" "hal_init_sound"   
   
    external load_wav: string -> sound 
        = "hal_load_wav" "hal_load_wav"
    
    external mute: bool -> unit = "hal_mute" "hal_mute"

    external lock_audio: unit -> unit = "hal_lock_audio" "hal_lock_audio"

    external unlock_audio: unit -> unit = "hal_unlock_audio" "hal_unlock_audio"
    
end

(***************************** End Audio **************************************)



(***************************** Events *****************************************)
module Event  = struct

	type app_state = APPMOUSEFOCUS | APPINPUTFOCUS | APPACTIVE 

	(* SDLKey enum *)
	type key = 
        | KEY_UNKNOWN	    
	    | KEY_FIRST		    
	    | KEY_BACKSPACE	    
	    | KEY_TAB		    
	    | KEY_CLEAR		    
	    | KEY_RETURN		
	    | KEY_PAUSE		    
	    | KEY_ESCAPE		
	    | KEY_SPACE		    
	    | KEY_EXCLAIM	    
	    | KEY_QUOTEDBL	    
	    | KEY_HASH		    
	    | KEY_DOLLAR		
	    | KEY_AMPERSAND	    
	    | KEY_QUOTE		    
	    | KEY_LEFTPAREN	    
	    | KEY_RIGHTPAREN	
	    | KEY_ASTERISK	    
	    | KEY_PLUS		    
	    | KEY_COMMA		    
	    | KEY_MINUS		    
	    | KEY_PERIOD		
	    | KEY_SLASH		    
	    | KEY_0			    
	    | KEY_1			    
	    | KEY_2			    
	    | KEY_3			    
	    | KEY_4			    
	    | KEY_5			    
	    | KEY_6			    
	    | KEY_7			    
	    | KEY_8			    
	    | KEY_9			    
	    | KEY_COLON		    
	    | KEY_SEMICOLON	    
	    | KEY_LESS		    
	    | KEY_EQUALS		
	    | KEY_GREATER	    
	    | KEY_QUESTION	    
	    | KEY_AT			
	    | KEY_LEFTBRACKET   
	    | KEY_BACKSLASH	    
	    | KEY_RIGHTBRACKET  
	    | KEY_CARET		    
	    | KEY_UNDERSCORE	
	    | KEY_BACKQUOTE 	
	    | KEY_a			    
	    | KEY_b			    
	    | KEY_c		    	
	    | KEY_d		    	
	    | KEY_e		    	
	    | KEY_f		    	
	    | KEY_g		    	
	    | KEY_h		    	
	    | KEY_i		    	
	    | KEY_j		    	
	    | KEY_k		    	
	    | KEY_l		    	
	    | KEY_m		    	
	    | KEY_n		    	
	    | KEY_o		    	
	    | KEY_p		    	
	    | KEY_q		    	
	    | KEY_r			    
	    | KEY_s			    
	    | KEY_t			    
	    | KEY_u			    
	    | KEY_v			    
	    | KEY_w			    
	    | KEY_x			    
	    | KEY_y		    	
	    | KEY_z			    
	    | KEY_DELETE		
	    | KEY_WORLD_0	    
	    | KEY_WORLD_1	    
	    | KEY_WORLD_2	    
	    | KEY_WORLD_3	    
	    | KEY_WORLD_4	    
	    | KEY_WORLD_5	    
	    | KEY_WORLD_6	    
	    | KEY_WORLD_7	    
	    | KEY_WORLD_8	    
	    | KEY_WORLD_9	    
	    | KEY_WORLD_10	    
	    | KEY_WORLD_11	    
	    | KEY_WORLD_12	    
	    | KEY_WORLD_13	    
	    | KEY_WORLD_14	    
	    | KEY_WORLD_15	    
	    | KEY_WORLD_16	    
	    | KEY_WORLD_17	    
	    | KEY_WORLD_18	    
	    | KEY_WORLD_19	    
	    | KEY_WORLD_20	    
	    | KEY_WORLD_21	    
	    | KEY_WORLD_22	    
	    | KEY_WORLD_23	    
	    | KEY_WORLD_24	    
	    | KEY_WORLD_25 	    
	    | KEY_WORLD_26	    
	    | KEY_WORLD_27	    
	    | KEY_WORLD_28	    
	    | KEY_WORLD_29	    
	    | KEY_WORLD_30	    
	    | KEY_WORLD_31	    
	    | KEY_WORLD_32	    
	    | KEY_WORLD_33	    
	    | KEY_WORLD_34 	    
	    | KEY_WORLD_35	    
	    | KEY_WORLD_36	    
	    | KEY_WORLD_37	    
	    | KEY_WORLD_38	    
	    | KEY_WORLD_39  	
	    | KEY_WORLD_40 	    
	    | KEY_WORLD_41	    
	    | KEY_WORLD_42  	
	    | KEY_WORLD_43	    
	    | KEY_WORLD_44	    
	    | KEY_WORLD_45	    
	    | KEY_WORLD_46	    
	    | KEY_WORLD_47	    
	    | KEY_WORLD_48	    
	    | KEY_WORLD_49	    
	    | KEY_WORLD_50	    
	    | KEY_WORLD_51 	    
	    | KEY_WORLD_52	    
	    | KEY_WORLD_53	    
	    | KEY_WORLD_54	    
	    | KEY_WORLD_55	    
	    | KEY_WORLD_56	    
	    | KEY_WORLD_57	    
	    | KEY_WORLD_58	    
	    | KEY_WORLD_59 	    
	    | KEY_WORLD_60	    
	    | KEY_WORLD_61	    
	    | KEY_WORLD_62	    
	    | KEY_WORLD_63	    
	    | KEY_WORLD_64	    
	    | KEY_WORLD_65	    
	    | KEY_WORLD_66	    
	    | KEY_WORLD_67	    
	    | KEY_WORLD_68	    
	    | KEY_WORLD_69	    
	    | KEY_WORLD_70	    
	    | KEY_WORLD_71	    
	    | KEY_WORLD_72	    
	    | KEY_WORLD_73	    
	    | KEY_WORLD_74  	
	    | KEY_WORLD_75	    
	    | KEY_WORLD_76	    
	    | KEY_WORLD_77	    
	    | KEY_WORLD_78	    
	    | KEY_WORLD_79	    
	    | KEY_WORLD_80	    
	    | KEY_WORLD_81	    
	    | KEY_WORLD_82	    
	    | KEY_WORLD_83	    
	    | KEY_WORLD_84 	    
	    | KEY_WORLD_85	    
	    | KEY_WORLD_86	    
	    | KEY_WORLD_87	    
	    | KEY_WORLD_88	    
	    | KEY_WORLD_89	    
	    | KEY_WORLD_90	    
	    | KEY_WORLD_91 	    
	    | KEY_WORLD_92	    
	    | KEY_WORLD_93  	
	    | KEY_WORLD_94	    
	    | KEY_WORLD_95	    
	    | KEY_KP0		    
	    | KEY_KP1		    
	    | KEY_KP2		    
	    | KEY_KP3		    
	    | KEY_KP4		    
	    | KEY_KP5	    	
	    | KEY_KP6		    
	    | KEY_KP7		    
	    | KEY_KP8		    
	    | KEY_KP9		    
	    | KEY_KP_PERIOD	    
	    | KEY_KP_DIVIDE	    
	    | KEY_KP_MULTIPLY   
	    | KEY_KP_MINUS	    
	    | KEY_KP_PLUS	    
	    | KEY_KP_ENTER	    
	    | KEY_KP_EQUALS	    
	    | KEY_UP			
	    | KEY_DOWN		    
	    | KEY_RIGHT		    
	    | KEY_LEFT		    
	    | KEY_INSERT		
	    | KEY_HOME		    
	    | KEY_END		    
	    | KEY_PAGEUP		
	    | KEY_PAGEDOWN	    
	    | KEY_F1			
	    | KEY_F2			
	    | KEY_F3			
	    | KEY_F4			
	    | KEY_F5			
	    | KEY_F6			
	    | KEY_F7			
	    | KEY_F8			
	    | KEY_F9			
	    | KEY_F10		    
	    | KEY_F11		    
	    | KEY_F12		    
	    | KEY_F13		    
	    | KEY_F14		    
	    | KEY_F15		    
	    | KEY_NUMLOCK	    
	    | KEY_CAPSLOCK	    
	    | KEY_SCROLLOCK	    
	    | KEY_RSHIFT		
	    | KEY_LSHIFT		
	    | KEY_RCTRL		    
	    | KEY_LCTRL		    
	    | KEY_RALT		    
	    | KEY_LALT		    
	    | KEY_RMETA		    
	    | KEY_LMETA		    
	    | KEY_LSUPER		
	    | KEY_RSUPER		
	    | KEY_MODE		    
	    | KEY_COMPOSE	    
	    | KEY_HELP		    
	    | KEY_PRINT		    
	    | KEY_SYSREQ		
	    | KEY_BREAK		    
	    | KEY_MENU		    
	    | KEY_POWER		    
	    | KEY_EURO		    
	    | KEY_UNDO		    
	    | KEY_LAST          
	
	(* SDLMod enum *)
	type key_mod = 
        | KMOD_NONE 
        | KMOD_LSHIFT 
        | KMOD_RSHIFT 
        | KMOD_LCTRL 
        | KMOD_RCTRL 
	    | KMOD_LALT 
        | KMOD_RALT 
        | KMOD_LMETA 
        | KMOD_RMETA
	    | KMOD_NUM 
        | KMOD_CAPS 
        | KMOD_MODE 

	type press_release = RELEASED | PRESSED
	
	type lost_gained = LOST | GAINED
	
	type active_event = {
		focus: lost_gained;
		state: app_state
	}
	
	type keyboard_event =  {
		keystate: press_release;
		scancode: int;
		sym: key;
		modifiers: key_mod list;
		unicode : int
	}
	
	type mouse_button =  LEFT | MIDDLE | RIGHT | WHEELUP | WHEELDOWN
	
	type mouse_motion_event = {
		mousestate : press_release;
		mx : int;
		my : int;
		mxrel : int;
		myrel : int
	}
	
	type mouse_button_event = {
		mousebutton: mouse_button;
		buttonstate: press_release;
		bx : int;
		by : int
	}
	
	type joy_axis_event = {
		which_axis : int;
		axis : int;
		jvalue : int
	}
		
	type joy_ball_event = {
		which_ball : int;
		ball : int;
		jxrel : int;
		jyrel : int
	}
	
	type joy_hat_event = {
		which_hat : int;
		hat : int;
		hvalue : int
	}
	
	type joy_button_event = {
		which_button : int;
		joybutton : int;
		jstate : press_release
	}
	
	type resize_event = {
		w : int;
		h : int
	}
	
	type user_event = {
        code  : int; 
        data1 : string; 
        data2 : string
    }

	type sys_wm_event
	
	type event = 
		| NOEVENT           
		| ACTIVE    of active_event     
		| KEY       of keyboard_event   
		| MOTION    of mouse_motion_event 
		| BUTTON    of mouse_button_event 
		| JAXIS     of joy_axis_event   
		| JBALL     of joy_ball_event   
		| JHAT      of joy_hat_event    
		| JBUTTON   of joy_button_event
		| RESIZE    of resize_event 
		| EXPOSE
		| QUIT 	        
		| USER      of user_event       
		| SYSWM     of sys_wm_event

    
    let default_repeat_delay = 500 and default_repeat_interval = 30
    
    let string_of_key_mod = function
        | KMOD_NONE     -> "KMOD_NONE" 
        | KMOD_LSHIFT   -> "KMOD_LSHIFT" 
        | KMOD_RSHIFT   -> "KMOD_RSHIFT" 
        | KMOD_LCTRL    -> "KMOD_LCTRL" 
        | KMOD_RCTRL    -> "KMOD_RCTRL"
	    | KMOD_LALT     -> "KMOD_LALT"
        | KMOD_RALT     -> "KMOD_RALT"
        | KMOD_LMETA    -> "KMOD_LMETA"
        | KMOD_RMETA    -> "KMOD_RMETA"
	    | KMOD_NUM      -> "KMOD_NUM"
        | KMOD_CAPS     -> "KMOD_CAPS"
        | KMOD_MODE     -> "KMOD_MODE"

    let string_of_key = function
        | KEY_UNKNOWN	     ->  "KEY_UNKNOWN"
	    | KEY_FIRST		     ->  "KEY_FIRST"
	    | KEY_BACKSPACE	     ->  "KEY_BACKSPACE"
	    | KEY_TAB		     ->  "KEY_TAB"
	    | KEY_CLEAR		     ->  "KEY_CLEAR"
	    | KEY_RETURN		 ->  "KEY_RETURN"
	    | KEY_PAUSE		     ->  "KEY_PAUSE"
	    | KEY_ESCAPE		 ->  "KEY_ESCAPE"
	    | KEY_SPACE		     ->  "KEY_SPACE"
	    | KEY_EXCLAIM	     ->  "KEY_EXCLAIM"
	    | KEY_QUOTEDBL	     ->  "KEY_QUOTEDBL"
	    | KEY_HASH		     ->  "KEY_HASH"
	    | KEY_DOLLAR		 ->  "KEY_DOLLAR"
	    | KEY_AMPERSAND	     ->  "KEY_AMPERSAND"
	    | KEY_QUOTE		     ->  "KEY_QUOTE"
	    | KEY_LEFTPAREN	     ->  "KEY_LEFTPAREN"
	    | KEY_RIGHTPAREN	 ->  "KEY_RIGHTPAREN"
	    | KEY_ASTERISK	     ->  "KEY_ASTERISK"
	    | KEY_PLUS		     ->  "KEY_PLUS"
	    | KEY_COMMA		     ->  "KEY_COMMA"
	    | KEY_MINUS		     ->  "KEY_MINUS"
	    | KEY_PERIOD		 ->  "KEY_PERIOD"
	    | KEY_SLASH		     ->  "KEY_SLASH"
	    | KEY_0			     ->  "KEY_0"
	    | KEY_1			     ->  "KEY_1"
	    | KEY_2			     ->  "KEY_2"
	    | KEY_3			     ->  "KEY_3"
	    | KEY_4			     ->  "KEY_4"
	    | KEY_5			     ->  "KEY_5"
	    | KEY_6			     ->  "KEY_6"
	    | KEY_7			     ->  "KEY_7"
	    | KEY_8			     ->  "KEY_8"
	    | KEY_9			     ->  "KEY_9"
	    | KEY_COLON		     ->  "KEY_COLON"
	    | KEY_SEMICOLON	     ->  "KEY_SEMICOLON"
	    | KEY_LESS		     ->  "KEY_LESS"
	    | KEY_EQUALS		 ->  "KEY_EQUALS"
	    | KEY_GREATER	     ->  "KEY_GREATER"
	    | KEY_QUESTION	     ->  "KEY_QUESTION"
	    | KEY_AT			 ->  "KEY_AT"
	    | KEY_LEFTBRACKET    ->  "KEY_LEFTBRACKET"
	    | KEY_BACKSLASH	     ->  "KEY_BACKSLASH"
	    | KEY_RIGHTBRACKET   ->  "KEY_RIGHTBRACKET"
	    | KEY_CARET		     ->  "KEY_CARET"
	    | KEY_UNDERSCORE	 ->  "KEY_UNDERSCORE"
	    | KEY_BACKQUOTE 	 ->  "KEY_BACKQUOTE"
	    | KEY_a			     ->  "KEY_a"
	    | KEY_b			     ->  "KEY_b"
	    | KEY_c		    	 ->  "KEY_c"
	    | KEY_d		    	 ->  "KEY_d"
	    | KEY_e		    	 ->  "KEY_e"
	    | KEY_f		    	 ->  "KEY_f"
	    | KEY_g		    	 ->  "KEY_g"
	    | KEY_h		    	 ->  "KEY_h"
	    | KEY_i		    	 ->  "KEY_i"
	    | KEY_j		    	 ->  "KEY_j"
	    | KEY_k		    	 ->  "KEY_k"
	    | KEY_l		    	 ->  "KEY_l"
	    | KEY_m		    	 ->  "KEY_m"
	    | KEY_n		    	 ->  "KEY_n"
	    | KEY_o		    	 ->  "KEY_o"
	    | KEY_p		    	 ->  "KEY_p"
	    | KEY_q		    	 ->  "KEY_q"
	    | KEY_r			     ->  "KEY_r"
	    | KEY_s			     ->  "KEY_s"
	    | KEY_t			     ->  "KEY_t"
	    | KEY_u			     ->  "KEY_u"
	    | KEY_v			     ->  "KEY_v"
	    | KEY_w			     ->  "KEY_w"
	    | KEY_x			     ->  "KEY_x"
	    | KEY_y		    	 ->  "KEY_y"
	    | KEY_z			     ->  "KEY_z"
	    | KEY_DELETE		 ->  "KEY_DELETE"
	    | KEY_WORLD_0	     ->  "KEY_WORLD_0"
	    | KEY_WORLD_1	     ->  "KEY_WORLD_1"
	    | KEY_WORLD_2	     ->  "KEY_WORLD_2"
	    | KEY_WORLD_3	     ->  "KEY_WORLD_3"
	    | KEY_WORLD_4	     ->  "KEY_WORLD_4"
	    | KEY_WORLD_5	     ->  "KEY_WORLD_5"
	    | KEY_WORLD_6	     ->  "KEY_WORLD_6"
	    | KEY_WORLD_7	     ->  "KEY_WORLD_7"
	    | KEY_WORLD_8	     ->  "KEY_WORLD_8"
	    | KEY_WORLD_9	     ->  "KEY_WORLD_9"
	    | KEY_WORLD_10	     ->  "KEY_WORLD_10"
	    | KEY_WORLD_11	     ->  "KEY_WORLD_11"
	    | KEY_WORLD_12	     ->  "KEY_WORLD_12"
	    | KEY_WORLD_13	     ->  "KEY_WORLD_13"
	    | KEY_WORLD_14	     ->  "KEY_WORLD_14"
	    | KEY_WORLD_15	     ->  "KEY_WORLD_15"
	    | KEY_WORLD_16	     ->  "KEY_WORLD_16"
	    | KEY_WORLD_17	     ->  "KEY_WORLD_17"
	    | KEY_WORLD_18	     ->  "KEY_WORLD_18"
	    | KEY_WORLD_19	     ->  "KEY_WORLD_19"
	    | KEY_WORLD_20	     ->  "KEY_WORLD_20"
	    | KEY_WORLD_21	     ->  "KEY_WORLD_21"
	    | KEY_WORLD_22	     ->  "KEY_WORLD_22"
	    | KEY_WORLD_23	     ->  "KEY_WORLD_23"
	    | KEY_WORLD_24	     ->  "KEY_WORLD_24"
	    | KEY_WORLD_25 	     ->  "KEY_WORLD_25"
	    | KEY_WORLD_26	     ->  "KEY_WORLD_26"
	    | KEY_WORLD_27	     ->  "KEY_WORLD_27"
	    | KEY_WORLD_28	     ->  "KEY_WORLD_28"
	    | KEY_WORLD_29	     ->  "KEY_WORLD_29"
	    | KEY_WORLD_30	     ->  "KEY_WORLD_30"
	    | KEY_WORLD_31	     ->  "KEY_WORLD_31"
	    | KEY_WORLD_32	     ->  "KEY_WORLD_32"
	    | KEY_WORLD_33	     ->  "KEY_WORLD_33"
	    | KEY_WORLD_34 	     ->  "KEY_WORLD_34"
	    | KEY_WORLD_35	     ->  "KEY_WORLD_35"
	    | KEY_WORLD_36	     ->  "KEY_WORLD_36"
	    | KEY_WORLD_37	     ->  "KEY_WORLD_37"
	    | KEY_WORLD_38	     ->  "KEY_WORLD_38"
	    | KEY_WORLD_39  	 ->  "KEY_WORLD_39"
	    | KEY_WORLD_40 	     ->  "KEY_WORLD_40"
	    | KEY_WORLD_41	     ->  "KEY_WORLD_41"
	    | KEY_WORLD_42  	 ->  "KEY_WORLD_42"
	    | KEY_WORLD_43	     ->  "KEY_WORLD_43"
	    | KEY_WORLD_44	     ->  "KEY_WORLD_44"
	    | KEY_WORLD_45	     ->  "KEY_WORLD_45"
	    | KEY_WORLD_46	     ->  "KEY_WORLD_46"
	    | KEY_WORLD_47	     ->  "KEY_WORLD_47"
	    | KEY_WORLD_48	     ->  "KEY_WORLD_48"
	    | KEY_WORLD_49	     ->  "KEY_WORLD_49"
	    | KEY_WORLD_50	     ->  "KEY_WORLD_50"
	    | KEY_WORLD_51 	     ->  "KEY_WORLD_51"
	    | KEY_WORLD_52	     ->  "KEY_WORLD_52"
	    | KEY_WORLD_53	     ->  "KEY_WORLD_53"
	    | KEY_WORLD_54	     ->  "KEY_WORLD_54"
	    | KEY_WORLD_55	     ->  "KEY_WORLD_55"
	    | KEY_WORLD_56	     ->  "KEY_WORLD_56"
	    | KEY_WORLD_57	     ->  "KEY_WORLD_57"
	    | KEY_WORLD_58	     ->  "KEY_WORLD_58"
	    | KEY_WORLD_59 	     ->  "KEY_WORLD_59"
	    | KEY_WORLD_60	     ->  "KEY_WORLD_60"
	    | KEY_WORLD_61	     ->  "KEY_WORLD_61"
	    | KEY_WORLD_62	     ->  "KEY_WORLD_62"
	    | KEY_WORLD_63	     ->  "KEY_WORLD_63"
	    | KEY_WORLD_64	     ->  "KEY_WORLD_64"
	    | KEY_WORLD_65	     ->  "KEY_WORLD_65"
	    | KEY_WORLD_66	     ->  "KEY_WORLD_66"
	    | KEY_WORLD_67	     ->  "KEY_WORLD_67"
	    | KEY_WORLD_68	     ->  "KEY_WORLD_68"
	    | KEY_WORLD_69	     ->  "KEY_WORLD_69"
	    | KEY_WORLD_70	     ->  "KEY_WORLD_70"
	    | KEY_WORLD_71	     ->  "KEY_WORLD_71"
	    | KEY_WORLD_72	     ->  "KEY_WORLD_72"
	    | KEY_WORLD_73	     ->  "KEY_WORLD_73"
	    | KEY_WORLD_74  	 ->  "KEY_WORLD_74"
	    | KEY_WORLD_75	     ->  "KEY_WORLD_75"
	    | KEY_WORLD_76	     ->  "KEY_WORLD_76"
	    | KEY_WORLD_77	     ->  "KEY_WORLD_77"
	    | KEY_WORLD_78	     ->  "KEY_WORLD_78"
	    | KEY_WORLD_79	     ->  "KEY_WORLD_79"
	    | KEY_WORLD_80	     ->  "KEY_WORLD_80"
	    | KEY_WORLD_81	     ->  "KEY_WORLD_81"
	    | KEY_WORLD_82	     ->  "KEY_WORLD_82"
	    | KEY_WORLD_83	     ->  "KEY_WORLD_83"
	    | KEY_WORLD_84 	     ->  "KEY_WORLD_84"
	    | KEY_WORLD_85	     ->  "KEY_WORLD_85"
	    | KEY_WORLD_86	     ->  "KEY_WORLD_86"
	    | KEY_WORLD_87	     ->  "KEY_WORLD_87"
	    | KEY_WORLD_88	     ->  "KEY_WORLD_88"
	    | KEY_WORLD_89	     ->  "KEY_WORLD_89"
	    | KEY_WORLD_90	     ->  "KEY_WORLD_90"
	    | KEY_WORLD_91 	     ->  "KEY_WORLD_91"
	    | KEY_WORLD_92	     ->  "KEY_WORLD_92"
	    | KEY_WORLD_93  	 ->  "KEY_WORLD_93"
	    | KEY_WORLD_94	     ->  "KEY_WORLD_94"
	    | KEY_WORLD_95	     ->  "KEY_WORLD_95"
	    | KEY_KP0		     ->  "KEY_KP0"
	    | KEY_KP1		     ->  "KEY_KP1"
	    | KEY_KP2		     ->  "KEY_KP2"
	    | KEY_KP3		     ->  "KEY_KP3"
	    | KEY_KP4		     ->  "KEY_KP4"
	    | KEY_KP5	    	 ->  "KEY_KP5"
	    | KEY_KP6		     ->  "KEY_KP6"
	    | KEY_KP7		     ->  "KEY_KP7"
	    | KEY_KP8		     ->  "KEY_KP8"
	    | KEY_KP9		     ->  "KEY_KP9"
	    | KEY_KP_PERIOD	     ->  "KEY_KP_PERIOD"
	    | KEY_KP_DIVIDE	     ->  "KEY_KP_DIVIDE"
	    | KEY_KP_MULTIPLY    ->  "KEY_KP_MULTIPLY"
	    | KEY_KP_MINUS	     ->  "KEY_KP_MINUS"
	    | KEY_KP_PLUS	     ->  "KEY_KP_PLUS"
	    | KEY_KP_ENTER	     ->  "KEY_KP_ENTER"
	    | KEY_KP_EQUALS	     ->  "KEY_KP_EQUALS"
	    | KEY_UP			 ->  "KEY_UP"
	    | KEY_DOWN		     ->  "KEY_DOWN"
	    | KEY_RIGHT		     ->  "KEY_RIGHT"
	    | KEY_LEFT		     ->  "KEY_LEFT"
	    | KEY_INSERT		 ->  "KEY_INSERT"
	    | KEY_HOME		     ->  "KEY_HOME"
	    | KEY_END		     ->  "KEY_END"
	    | KEY_PAGEUP		 ->  "KEY_PAGEUP"
	    | KEY_PAGEDOWN	     ->  "KEY_PAGEDOWN"
	    | KEY_F1			 ->  "KEY_F1"
	    | KEY_F2			 ->  "KEY_F2"
	    | KEY_F3			 ->  "KEY_F3"
	    | KEY_F4			 ->  "KEY_F4"
	    | KEY_F5			 ->  "KEY_F5"
	    | KEY_F6			 ->  "KEY_F6"
	    | KEY_F7			 ->  "KEY_F7"
	    | KEY_F8			 ->  "KEY_F8"
	    | KEY_F9			 ->  "KEY_F9"
	    | KEY_F10		     ->  "KEY_F10"
	    | KEY_F11		     ->  "KEY_F11"
	    | KEY_F12		     ->  "KEY_F12"
	    | KEY_F13		     ->  "KEY_F13"
	    | KEY_F14		     ->  "KEY_F14"
	    | KEY_F15		     ->  "KEY_F15"
	    | KEY_NUMLOCK	     ->  "KEY_NUMLOCK"
	    | KEY_CAPSLOCK	     ->  "KEY_CAPSLOCK"
	    | KEY_SCROLLOCK	     ->  "KEY_SCROLLOCK"
	    | KEY_RSHIFT		 ->  "KEY_RSHIFT"
	    | KEY_LSHIFT		 ->  "KEY_LSHIFT"
	    | KEY_RCTRL		     ->  "KEY_RCTRL"
	    | KEY_LCTRL		     ->  "KEY_LCTRL"
	    | KEY_RALT		     ->  "KEY_RALT"
	    | KEY_LALT		     ->  "KEY_LALT"
	    | KEY_RMETA		     ->  "KEY_RMETA"
	    | KEY_LMETA		     ->  "KEY_LMETA"
	    | KEY_LSUPER		 ->  "KEY_LSUPER"
	    | KEY_RSUPER		 ->  "KEY_RSUPER"
	    | KEY_MODE		     ->  "KEY_MODE"
	    | KEY_COMPOSE	     ->  "KEY_COMPOSE"
	    | KEY_HELP		     ->  "KEY_HELP"
	    | KEY_PRINT		     ->  "KEY_PRINT"
	    | KEY_SYSREQ		 ->  "KEY_SYSREQ"
	    | KEY_BREAK		     ->  "KEY_BREAK"
	    | KEY_MENU		     ->  "KEY_MENU"
	    | KEY_POWER		     ->  "KEY_POWER"
	    | KEY_EURO		     ->  "KEY_EURO"
	    | KEY_UNDO		     ->  "KEY_UNDO"
	    | KEY_LAST           ->  "KEY_LAST"
   
    let string_of_event = function
	    | NOEVENT	 -> "NOEVENT"
	    | ACTIVE  a  -> "ACTIVE"
	    | KEY     k  -> "KEY"
	    | MOTION  m  -> "MOTION"
	    | BUTTON  b  -> "BUTTON"
	    | JAXIS   ja -> "JAXIS"
	    | JBALL   jb -> "JBALL"
	    | JHAT 	  jh -> "JHAT"
	    | JBUTTON jn -> "JBUTTON"
	    | RESIZE  r	 -> "RESIZE"
	    | EXPOSE     -> "EXPOSE"
	    | QUIT 		 -> "QUIT"
	    | USER 	  u	 -> "USER" 
	    | SYSWM   s  -> "SYSWM"

    
(** Get the application state
    Example usage:
        let app_has_mouse_focus = get_app_state APPMOUSEFOCUS
    @param app_state 
    @return true if the application is in that state, else false *)    
	external get_app_state: app_state -> bool 
        = "hal_get_app_state" "hal_get_app_state"	    

(** Enable key repeat
    @param delay how long the key must be pressed in ms before it start repeating
    @param interval length of time between repeats in ms *)	
	external enable_key_repeat: delay:int -> interval:int -> unit 
        = "hal_enable_key_repeat" "hal_enable_key_repeat"
    
(** Get the states of key modifiers
    Example usage
        pump_events ();
        let mod_list = get_mod_state () in 
        List.iter (fun i -> printf "%s\n" (string_of_key_mod i)) mod_list;
    @return list of pressed key modifiers *)
	external get_mod_state : unit -> (key_mod list) 
        = "hal_get_mod_state" "hal_get_mod_state"
	
(** Places input from input devices on the event queue *)
	external pump_events : unit -> unit = "hal_pump_events" "hal_pump_events"

(** Pops and returns the first event on the event queue. 
    Example usage
        let e = poll_event ()
    @return event. If there are no events, NoEvent is returned *)    
	external poll_event : unit -> event = "hal_poll_event" "hal_poll_event"

(** Waits for an event to be placed on the event queue. 
    After a (short, < 1 sec) timeout wait_event returns NOEVENT 
    if there were no events
    Example usage
        let e = wait_event ()
    @return event. If there are no events, NOEVENT is returned *)    
	external wait_event : unit -> event = "hal_wait_event" "hal_wait_event"
    
(** Pushes a user event onto the event queue 
    Example usage: 
        push_event { code = 0; data1 = "Hello"; data2 = "world" } 
    @param user_event event to be placed on the event queue *)
    external push_event : user_event -> unit = "hal_push_event" "hal_push_event"

end
(***************************** End Events. ************************************)


(****************************** Mouse *****************************************)
module Mouse = struct

(** Set the position of the mouse cursor (generates a mouse motion event) 
    @param x x-position to move mouse to 
    @param y y-position to move mouse to *)  
    external warp_mouse: int -> int -> unit = "hal_warp_mouse" "hal_warp_mouse"

(**  Toggles the visibility of the mouse cursor
    @param visible if true shows the mouse cursor. If false, hides the cursor *)
    external show_cursor : bool -> unit = "hal_show_cursor" "hal_show_cursor"
end
(****************************** End Mouse *************************************)


(****************************** Time ******************************************)
module Time  = struct

(** Delay program execution for a specified number of milliseconds 
    @param ms interval in milliseconds *)
    external delay: int -> unit = "hal_delay" "hal_delay"

(** Get number of ticks since HAL initialization *)    
    external get_ticks: unit -> int = "hal_get_ticks" "hal_get_ticks"

end
(****************************** End Time **************************************)


(****************************** Video *****************************************)
module Video  = struct

    type surface

end
(****************************** End Video *************************************)


(****************************** Window management *****************************)
module Window  = struct

(** Gets the title-bar and icon name of the display window.
    @result *)
    external get_caption : unit -> string * string 
        = "hal_get_caption" "hal_get_caption"
	
(** Iconifies or minimises window to desktop or task bar *)	
    external iconify_window : unit -> unit 
        = "hal_iconify_window" "hal_iconify_window"
    
(** Create a window
    @param width horizontal resolution in pixels
    @param height vertical resolution in pixels
    @param bpp colour depth in bits per pixel
    @raise Failure error-message *)
    external make_window: width:int -> height:int -> bpp:int -> unit 
        = "hal_set_video_mode" "hal_set_video_mode"

(** Sets the title-bar and icon name of the display window.
    @param title-bar name
    @param icon name *)
	external set_caption : string -> string -> unit 
        = "hal_set_caption" "hal_set_caption"
	
(** Toggles fullscreen mode *)    
    external toggle_fullscreen : unit -> unit 
        = "hal_toggle_fullscreen" "hal_toggle_fullscreen"
	
(** Grabs mouse and keyboard input 
    @param true grab input, false give input back to window manager *)    
    external set_grab_input : bool -> unit 
        = "hal_set_grab_input" "hal_set_grab_input"

end
(****************************** End Window management *************************)

